//USER omp
//$Id: user_omp.h 608 2010-11-28 16:30:05Z andrew.tsyganov $
#pragma once

#include "src/heo/include/easy_omp.h"
#include "src/heo/include/xml_file.h"
#include "user_common.h"

//__________________________________________________________________________________
template<class T, class U>
class user_OMP:
    public user_solver<T>
{
public:
    typedef typename user_solver<T>::TEnvironment TEnvironment;
    typedef typename user_solver<T>::TSolution    TSolution;

    typedef typename user_solver<T>::TDirection   TDirection;
    typedef typename user_solver<T>::TCostType    TCostType;


public:
    template<class TSolutionPool, class TStatistics>
    void solve(TSolutionPool& pool, TStatistics& stat)
    {
        int np = omp_get_max_threads();
        omp::solver_fork< TSolutionPool, TStatistics, U > f(pool, stat, static_cast<U&>(*this));
        omp::communicator::run(np, f);
    }

    template<class TInOutSolution, class TStatistics>
    void solve_OMP(Solution_Pool<TInOutSolution>& pool,
        TStatistics& stat,
        omp::communicator& comm)
    {
        ASSERT_(this->rank_ == comm.rank());
        int np   = comm.size();

        init_From_Pool(pool);
        this->user_Solve(pool, stat, np);
        this->clear_OMP(comm);

        update_Pool(pool, comm, np);
    }

private:
    void clear_OMP(omp::communicator& comm)
    {
        comm.barrier();
        //comm.clear_Data();
        //comm.barrier();
    }

    template<class TInOutSolution>
    void update_Pool(Solution_Pool<TInOutSolution>& pool, omp::communicator& comm, int np)
    {
        if (0 == this->rank_)
        {
            pool.sol_list_.resize(np);
        }
        comm.barrier();

        TSolution const& final_sol = this->get_Final_Solution();
        //:final_sol --> pool

        TInOutSolution& it = pool.sol_list_[this->rank_];
        it.init(this->env_, this->rnd_);
        it.assign(final_sol);

#pragma omp critical
        {
            if (this->get_Debug_Level())
            {
                std::cout << lf 
                          << this->rank_ << ": final cost = " << final_sol.get_Cost() << lf;
            }
        }
    }
};
//__________________________________________________________________________________
//__________________________________________________________________________________

//EOF!
